#ifndef AVALON_AESDECODER_HPP
#define AVALON_AESDECODER_HPP
#include <boost/scoped_array.hpp>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/secblock.h>
#include "Avalon/Codecs/Decoder.hpp"

namespace Avalon {
namespace Codecs {

  /*! \class AesDecoder
   *  \brief Decodes an AES-256 encrypted message.
   *  \author Kamal Mansouri <kranar@hotmail.com>
   */
  class AesDecoder : public Decoder {
    public:

      //! Establishes a client-side AES-256 Channel.
      /*!
        \param channel The existing Channel to secure.
        \param encodeInPlace Set to <code>true</code> to encode in place.
        \return An AES-256 encrypted Channel.
      */
      static IO::Channel* EstablishClientChannel(IO::Channel* channel,
        bool encodeInPlace = false);

      //! Establishes a server-side AES-256 Channel.
      /*!
        \param channel The existing Channel to secure.
        \param encodeInPlace Set to <code>true</code> to encode in place.
        \return An AES-256 encrypted Channel.
      */
      static IO::Channel* EstablishServerChannel(IO::Channel* channel,
        bool encodeInPlace = false);

      //! Creates an AesDecoder.
      /*!
        \param key The encryption key.
        \param iv The encryption iv.
      */
      AesDecoder(const CryptoPP::SecByteBlock& key, const byte* iv);

      virtual ~AesDecoder();

      virtual bool IsDecodeInPlaceSupported();

      virtual void Decode(const void* source, int sourceSize,
        void* destination, int destinationSize, int* decodedSize = NULL);

      virtual void Decode(const void* source, int sourceSize,
        IO::Buffer* destination, int* decodedSize = NULL);

      using Decoder::Decode;

      using Decoder::DecodeInPlace;

    private:
      CryptoPP::SecByteBlock m_key;
      boost::scoped_array<byte> m_iv;
      CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_decoder;
  };
}
}

#endif // AVALON_AESDECODER_HPP
